#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>

/* set_opt(fd,115200,8,'N',1) */
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
	struct termios newtio,oldtio;
	
	if ( tcgetattr( fd,&oldtio) != 0) {   //获取终端属性
		perror("SetupSerial 1");
		return -1;
	}
	
	bzero( &newtio, sizeof( newtio ) ); //置字符串s的前n个字节为零且包括‘\0’
	newtio.c_cflag |= CLOCAL | CREAD; 
	newtio.c_cflag &= ~CSIZE; 

	newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
	newtio.c_oflag  &= ~OPOST;   /*Output*/

	switch( nBits ) //几位数据位
	{
	case 7:
		newtio.c_cflag |= CS7;
	break;
	case 8:
		newtio.c_cflag |= CS8;
	break;
	}

	switch( nEvent ) //校验位
	{
	case 'O':
		newtio.c_cflag |= PARENB;
		newtio.c_cflag |= PARODD;
		newtio.c_iflag |= (INPCK | ISTRIP);
	break;
	case 'E': 
		newtio.c_iflag |= (INPCK | ISTRIP);
		newtio.c_cflag |= PARENB;
		newtio.c_cflag &= ~PARODD;
	break;
	case 'N': 
		newtio.c_cflag &= ~PARENB;
	break;
	}

	switch( nSpeed ) //波特率
	{
	case 2400:
		cfsetispeed(&newtio, B2400); //设置输入波特率
		cfsetospeed(&newtio, B2400); //设置输出波特率
	break;
	case 4800:
		cfsetispeed(&newtio, B4800);
		cfsetospeed(&newtio, B4800);
	break;
	case 9600:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
	break;
	case 115200:
		cfsetispeed(&newtio, B115200);
		cfsetospeed(&newtio, B115200);
	break;
	default:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
	break;
	}
	
	if( nStop == 1 )  //几位停止位
		newtio.c_cflag &= ~CSTOPB;
	else if ( nStop == 2 )
		newtio.c_cflag |= CSTOPB;

	
	newtio.c_cc[VMIN]  = 1;  /* 读数据时的最小字节数: 没读到这些数据我就不返回! */
	newtio.c_cc[VTIME] = 0; /* 等待第1个数据的时间: 
	                         * 比如VMIN设为10表示至少读到10个数据才返回,
	                         * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)
	                         * 假设VTIME=1，表示: 
	                         *    10秒内一个数据都没有的话就返回
	                         *    如果10秒内至少读到了1个字节，那就继续等待，完全读到VMIN个数据再返回
	                         */

	tcflush(fd,TCIFLUSH);  //清空终端未完成的输入/输出请求及数据
	
	if((tcsetattr(fd,TCSANOW,&newtio))!=0)  //修改终端参数
	{
		perror("com set error");
		return -1;
	}
	//printf("set done!\n");
	return 0;
}

int open_port(char *com)
{
	int fd;
	//fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
	fd = open(com, O_RDWR|O_NOCTTY);//O_NOCTTY：不把串口数据当作控制终端，纯数据
    if (-1 == fd){return(-1);}

	/*
	fcntl(fd, F_SETFL, FNDELAY)	读数据时不等待，没有数据就返回0
	fcntl(fd, F_SETFL, 0)		读数据时等待，没有数据时 阻塞
	*/	
	if(fcntl(fd, F_SETFL, 0)<0) /* 设置串口为阻塞状态*/
	{
		printf("fcntl failed!\n");
		return -1;
	}
  
	return fd;
}

//读取一行数据
int read_gps_raw_data(int fd,char* buf)
{
	int iRet;
	char c;
	int i=0;
	int startflag = 0;//读数据标志位
	while(1)
	{
		iRet = read(fd, &c, 1);
		if (iRet == 1)
		{
			if(c == '$') //第一个字符
				startflag = 1;
			if(startflag ==1)
			{
				buf[i++]=c;
			}
			if(c =='\n'  || c=='\r')
			{
				return 0; //表示成功
			}		
		}			
		else
			return -1;
	}
}

struct GPS_data
{
	char* xxGGA;
	char* time; //UTC时间
	char* lat; 	//纬度
	char* ns; 	//南北半球
	char* lng; 	//经度
	char* ew; 	//东西半球
};

int parse_gps_raw_data(char* buf,struct GPS_data gps_data)
{
	/*例子：$GPGGA，074529.82，2429.6717，N，11804.6973，E，1，8，1.098，42.110，，，M，，*76*/
	/*格式：单GPS，UTC时间，纬度，南北半球，经度，东西半球，GPS状态，卫星数，HDOP，
			海拔，高程异常，差分时间，参考站号*/
	if(buf[0] != '$') return -1;//检验 '$'
	else if(strncmp(buf+3,"GGA",3) != 0) return -1;// 检验 'GGA'
	else if(strstr(buf,",,,,,")){printf("Place the GPS to open area\n");return -1;}//检查GPS开没开
	else	
	{
		sscanf(buf,"%s,%s,%s,%s,%s,%s,",gps_data.xxGGA,gps_data.time,gps_data.lat, 
											gps_data.ns,gps_data.lng,gps_data.ew);
		return 0;
	}		
}


/*
 * ./serial_send_recv <dev>
 * 1. open 
 * 2. setup 
 	* 115200,8N1
  	* RAW mode
  	* return data immediately
 * 3. write and read 
 */
int main(int argc, char **argv)
{
	int fd;
	int iRet;
	char c;
	char buf[1000];
	struct GPS_data gps_data;
	
	if (argc != 2)
	{
		printf("Usage: \n");
		printf("%s </dev/ttySAC1 or other>\n", argv[0]);
		return -1;
	}

	//1. open
	fd = open_port(argv[1]);
	if (fd < 0)
	{printf("open %s err!\n", argv[1]);return -1;}

	//2. setup  (115200,8N1 | RAW mode | return data immediately)
	iRet = set_opt(fd, 9600, 8, 'N', 1);//波特率:9600,八位数据位，无校验，一位停止位
	if (iRet){printf("set port err!\n");return -1;}
	printf("Enter a char: ");

	//3. write and read
	while (1)
	{
		float fLat,fLng;
		//读数据
		iRet = read_gps_raw_data(fd,buf);
		//解析数据
		if(iRet ==0)
		{
			iRet = parse_gps_raw_data(buf,gps_data);
			if(iRet ==0)
			{
				//打印
				printf("Time: %s\n",gps_data.time);
				printf("ns: %s\n",gps_data.ns);
				printf("ew: %s\n",gps_data.ew);
				
				/* 经纬度格式：ddmm.mmmm = dd+(mm.mmmm/60)*/
				sscanf(gps_data.lat+2,"%f",&fLat);//后两位和小数位
				fLat = fLat/60;
				fLat += (gps_data.lat[0]-'0')*10 + gps_data.lat[1]-'0';//加上头两位
				sscanf(gps_data.lng+3,"%f",&fLng);//后两位和小数位
				fLng = fLng/60;
				fLng += (gps_data.lng[0]-'0')*100 + (gps_data.lng[1]-'0')*10   //加上头三位
						+gps_data.lng[2]-'0';
				printf("Lng,Lat %.06f,%.06f\n",fLng,fLat);
			}
		}			
	}
	return 0;
}

